package timer

import (
	"fmt"
	jsoniter "github.com/json-iterator/go"
	"github.com/robfig/cron/v3"
	"go_gui/lib"
	"go_gui/logger"
)

// 使用举例：
// 每隔5秒执行一次：*/5 * * * * *
// 每隔1分钟执行一次：0 */1 * * * *
// 每天23点执行一次：0 0 23 * * *
// 每月1号凌晨1点执行一次：0 0 1 1 * *
// 在26分、29分、33分执行一次：0 26,29,33 * * * *
// 每天的0点、13点、18点、21点都执行一次：0 0 0,13,18,21 * * *

type ManageStruct struct {
	*cron.Cron
	/*
		定时器key对应的id
		例如：
			Name2EntryId = {
				“user.timer_hello": 1
			}
	*/
	Name2EntryId map[string]cron.EntryID
}

type Func func(args ...any) string
type Api2Func map[string]Func

/*
	所属模块对应的定时器名字和方法引用
	例如：
		Folder2Name2Func = {
			"user": {
				"timer_hello" TimerHello,
			}
		}
*/
var Folder2Api2Func = make(map[string]Api2Func)

func NewTimer() *ManageStruct {
	return &ManageStruct{
		Cron:         cron.New(cron.WithSeconds()),
		Name2EntryId: make(map[string]cron.EntryID),
	}
}

type TimerInfo struct {
	TimerStr string `json:"timerstr"` // 定时器规则
	Folder   string `json:"folder"`   // 所属模块
	Api      string `json:"api"`      // 定时器名字
	Args     []any  `json:"args"`     //定时器参数
	Desc     string `json:"desc"`     // 定时器描述
}

// Run 开启定时器
func (m *ManageStruct) Run(jsonName string) {
	m.InitTimers(jsonName)
	m.Start()
}

// InitTimers 初始化定时器
func (m *ManageStruct) InitTimers(jsonName string) {
	_timerInfoList := LoadConfig(jsonName)
	m.AddTimers(_timerInfoList)

}

// AddTimers 加载定时器
func (m *ManageStruct) AddTimers(timerInfoList []*TimerInfo) {
	logger.Print("**********************************************************************************************")
	logger.Print("定时器加载ing...")
	// 初始化定时器
	for _, timerInfo := range timerInfoList {
		_name2Func, ok := Folder2Api2Func[timerInfo.Folder]
		if !ok {
			logger.TimerLog.Warn(fmt.Sprintf("【%s】模块未注册定时器!!", timerInfo.Folder))
			continue
		}
		_func, ok := _name2Func[timerInfo.Api]
		if !ok {
			logger.TimerLog.Warn(fmt.Sprintf("【%s】模块【%s】定时器不存在!!", timerInfo.Folder, timerInfo.Api))
			continue
		}

		// 封装job，捕获任务状态
		_job := &Job{
			F:    _func,
			Args: timerInfo.Args,
			Key:  fmt.Sprintf("%s.%s", timerInfo.Folder, timerInfo.Api),
		}
		_entryId, err := m.AddJob(timerInfo.TimerStr, _job)
		if err != nil {
			logger.TimerLog.Warn(fmt.Sprintf("【%s】模块【%s】定时器AddFunc失败!! err-->%s", timerInfo.Folder, timerInfo.Api, err.Error()))
			continue
		}

		_key := fmt.Sprintf("%s.%s", timerInfo.Folder, timerInfo.Api)
		m.Name2EntryId[_key] = _entryId
		logger.Print(
			"addTimer: %s   timerStr: %s  desc: %s",
			_key, timerInfo.TimerStr, timerInfo.Desc,
		)
	}
	logger.Print("**********************************************************************************************")
}

// LoadConfig 加载定时器配置
func LoadConfig(fileName string) []*TimerInfo {
	// 文件路径校验
	_filePath := lib.GetFilePath(fmt.Sprintf("json/%s.json", fileName))
	if !lib.IsFileExist(_filePath) {
		logger.TimerLog.Warn(fmt.Sprintf("定时器配置文件【%s】不存在!!", fileName))
		return nil
	}

	// 读取文件内容
	_fileData := lib.ReadFile(_filePath)

	// 解析文件内容
	var (
		_dataList []map[string]any
		err       error
	)
	// 转换成[]map[string]any
	err = jsoniter.Unmarshal(_fileData, &_dataList)
	if err != nil {
		logger.TimerLog.Warn(fmt.Sprintf("定时器配置文件【%s】解析失败!! err-->%s", fileName, err.Error()))
		return nil
	}

	var timerInfoList []*TimerInfo
	for _, data := range _dataList {
		timerInfo := new(TimerInfo)
		lib.Convert.Map2Struct(data, &timerInfo)
		if timerInfo == nil {
			logger.TimerLog.Warn(fmt.Sprintf("定时器配置【%+v】格式错误!!", data))
			continue
		}
		timerInfoList = append(timerInfoList, timerInfo)
	}

	return timerInfoList

}

// Register 注册定时器
func Register(folder string, name2Func Api2Func) {
	_, ok := Folder2Api2Func[folder]
	if ok {
		logger.TimerLog.Warn(fmt.Sprintf("【%s】模块重复注册定时器!!", folder))
		return
	}

	Folder2Api2Func[folder] = name2Func

}
